package com.cskaoyan.javase.array._5operation._3retrieve;

import java.util.Arrays;

/**
 * 数组的查找
 * 日常开发中,我们最常见的需求就是"增删改查"(往往是基于数据库)
 * 现在我们没有数据库,我们把数组当成一个容器,来完成对数组的增删改查
 * 增: Create
 * 查: Retrieve
 * 删: Delete
 * 改: Update
 *
 *
 * @since 11:12
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class NewDemo {
    public static void main(String[] args) {
        String[] arr = new String[10];
        arr[0] = "张三";
        arr[1] = "李四";
        arr[2] = "王二";
        arr[3] = "麻子";
        // 测试一下新增
        System.out.println("新增之前:" + Arrays.toString(arr));
        create(arr, "长风");
        System.out.println("新增之后:" + Arrays.toString(arr));
        System.out.println("----------------------------------------------------");
        String s1 = new String("123");
        String s2 = new String("123");
        // 双等号比较地址,对于String而言,如果想要比较内容,需要使用方法equals去比较
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
        System.out.println("----------------------------------------------------");
        arr[2] = null;
        System.out.println("删除长风之前:" + Arrays.toString(arr));
        delete(arr, "长风");
        System.out.println("删除长风之后:" + Arrays.toString(arr));
        System.out.println("----------------------------------------------------");
        System.out.println("修改张三之前:" + Arrays.toString(arr));
        update(arr, "张三", "法外狂徒");
        System.out.println("修改张三之后:" + Arrays.toString(arr));
        System.out.println("----------------------------------------------------");
        create(arr, "麻子");
        System.out.println("数组是:" + Arrays.toString(arr));
        System.out.println("查找的第一个麻子:" + getFirstTargetElementIndex(arr, "麻子"));
        System.out.println("查找的最后一个麻子:" + getLastTargetElementIndex(arr, "麻子"));


    }


    // 写方法完成String数组的新增元素的操作
    /*
        数组能不能真正的直接新增一个元素?
        不能,所以我们这里的新增是替换,将某个默认值,替换成我们想要的值
        既然是新增,我们给出一个返回值,来表示新增操作是否成功
     */
    public static boolean create(String[] arr, String param) {
        // 替换默认值为新的String对象,需要遍历数组,找到null元素,替换
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == null) {
                arr[i] = param;
                // 表示新增成功
                return true;
            }
        }
        // 程序运行到这里,说明数组中已经不存在null元素,说明数组满了,没有位置了,新增失败
        System.out.println("数组满了,没有位置了!新增失败!");
        return false;
    }


    // 删除元素,不是真正删除,而是把元素替换成默认值null

    /**
     * 删除成功返回true,否则返回false
     * @since 11:25
     * @param arr 被删除元素的数组
     * @param target 要删除的目标元素
     * @return boolean
     * @author wuguidong@cskaoyan.onaliyun.com
     */
    public static boolean delete(String[] arr, String target) {
        // 首先要查找目标元素是否存在
        /*
            怎么查找一个String对象呢? 能用"=="吗?
            双等号比较的是地址,需要用equals比较内容
          */
        /*for (int i = 0; i < arr.length; i++) {
            // 避免空指针异常,最简单的方法就是if判断
            if (arr[i] == null) {
                // 直接跳过循环,避免空指针异常
                continue;
            }
            if (arr[i].equals(target)) {
                // 找到元素,就将它替换成null
                arr[i] = null;
                // 删除成功
                return true;
            }
        }*/
        // 直接调用查找目标元素下标的方法(默认数组中的元素是唯一的)
        int targetIndex = getFirstTargetElementIndex(arr, target);
        // 判断是否找到该元素
        if (targetIndex != -1) {
            // 找到了元素,就删除
            arr[targetIndex] = null;
            return true;
        }
        // 代码运行到这里,说明没有找到目标元素,删除失败
        System.out.println("没有找到目标元素,删除失败");
        return false;
    }

    // 修改String中元素的取值

    /**
     * 修改数组中元素的取值,修改成功返回true,否者返回false
     * @since 11:42
     * @param arr 要修改元素的数组
     * @param target 要被修改的目标元素
     * @param newValue 修改后的取值
     * @return boolean
     * @author wuguidong@cskaoyan.onaliyun.com
     */
    public static boolean update(String[] arr, String target, String newValue) {
        // 首先要查找目标元素是否存在
       /* for (int i = 0; i < arr.length; i++) {
            // 避免空指针异常,最简单的方法就是if判断
            if (arr[i] == null) {
                // 直接跳过循环,避免空指针异常
                continue;
            }
            if (arr[i].equals(target)) {
                // 找到元素,就将它替换成newValue
                arr[i] = newValue;
                // 修改成功
                return true;
            }
        }*/
        // 直接调用查找目标元素下标的方法(默认数组中的元素是唯一的)
        int targetIndex = getFirstTargetElementIndex(arr, target);
        // 判断是否找到该元素
        if (targetIndex != -1) {
            // 找到了元素,就替换
            arr[targetIndex] = newValue;
            return true;
        }
        // 代码运行到这里,说明没有找到目标元素,修改失败
        System.out.println("没有找到目标元素,修改失败");
        return false;
    }

    // 查找目标元素,如果找到了,就返回目标元素存在的下标

    /**
     * 如果找到目标元素,就返回它的下标
     * @since 11:46
     * @param arr 被查找元素的数组
     * @param target 目标元素
     * @return int
     * @author wuguidong@cskaoyan.onaliyun.com
     */
    public static int getFirstTargetElementIndex(String[] arr, String target) {
        // 预先定义一个返回结果的下标
        int resultIndex = -1;
        for (int i = 0; i < arr.length; i++) {
            // 避免空指针异常,最简单的方法就是if判断
            if (arr[i] == null) {
                // 直接跳过循环,避免空指针异常
                continue;
            }
            if (arr[i].equals(target)) {
                // 找到目标元素,i就是目标下标
                resultIndex = i;
                return resultIndex;
            }
        }
        // 代码运行到这里,说明没有找到目标元素,那返回下标返回-1
        /*
            直接return -1;是没有大问题的,但是有小问题,这就牵扯一个写代码的规范
            像-1,"hello"这种字面值常量,它是没有名字的,这种值如果刚写完,代码是可以读懂的.
            但时间比较久了,没有名字就不知道它的用途了
            这种直接写在代码中字面值,叫做"魔法值",魔法值在代码中最好不要写,写魔法值对代码块可读性不好
         */
        return resultIndex;
    }

    // 查找目标元素最后在数组中的位置
    public static int getLastTargetElementIndex(String[] arr, String target) {
        // 预先定义一个返回结果的下标
        int resultIndex = -1;
        for (int i = arr.length - 1; i >= 0; i--) {
            // 避免空指针异常,最简单的方法就是if判断
            if (arr[i] == null) {
                // 直接跳过循环,避免空指针异常
                continue;
            }
            if (arr[i].equals(target)) {
                // 找到目标元素,i就是目标下标
                resultIndex = i;
                return resultIndex;
            }
        }
        // 代码运行到这里,说明没有找到目标元素,那返回下标返回-1
        /*
            直接return -1;是没有大问题的,但是有小问题,这就牵扯一个写代码的规范
            像-1,"hello"这种字面值常量,它是没有名字的,这种值如果刚写完,代码是可以读懂的.
            但时间比较久了,没有名字就不知道它的用途了
            这种直接写在代码中字面值,叫做"魔法值",魔法值在代码中最好不要写,写魔法值对代码块可读性不好
         */
        return resultIndex;
    }


}
